package com.javapandeng.controller;

import java.lang.reflect.Field;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

public class DataConnection<T>  {
    //连接数据库的驱动程序的字符常量
    private static final String DBDRIVER = "org.gjt.mm.mysql.Driver";
    //连接数据库地址,其中jdbc是连接数据库的主协议;mysql是子协议;localhost:3306是我们在本机上安装的mysql数据库管理服务器名，stsc是在myssql数据库系统中创建的数据库名
    private static final String DBURL = "jdbc:mysql://localhost:3306/shopdata";
    //连接数据库管理员，是mysql数据库的系统管理员root
    private static final String DBUSER = "root";
    //连接数据库管理员登录密码,是在安装mysql数据库时，给定的密码
    private static final String DBPASS = "admin";
    private static Connection conn = null;
    private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    /**
     * 方法用于获取数据库连接对象
     *
     * @return 连接成功返回数据库连接对象（Connection类的对象）
     */
    public static Connection getConn() {
        try {
            //加载驱动程序
            Class.forName(DBDRIVER);
            //获取数据库连接对象
            conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
            //连接成功返回连接对象
            return conn;
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
            //如果连接失败返回null
            return conn;
        }
    }

    /**
     * 用于对数据库操作对象进行关闭操作,一般对数据库进行操作对象都是这三个类（ResultSet,PreparedStatement ,Connection ）的对象
     *
     * @param rs   保存从数据表取加的数据集
     * @param psta 执行sql命令的对象
     * @param conn 连接数据对象
     */
    public static void close(ResultSet rs, PreparedStatement psta, Connection conn) {
        try {
            //判断rs不为空，则它存在，就关闭它
            if (rs != null) {
                rs.close();
            }
            //判断psta不为空，则它存在，就关闭它
            if (psta != null) {
                psta.close();
            }
            //判断conn不为空，则它存在，就关闭它
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 执行insert、update和delete命令的方法
     *
     * @param sqlcomm sql命令字符串
     * @param para    sql命令中参数参数所对应的值
     * @return 执行命令成功返回true，否则返回false
     */
    public static boolean request(String sqlcomm, Object... para) {
        boolean flag = false;
        try {
            //创建数据库连接
            Connection conn = getConn();
            //创建执行sql命令的对象
            PreparedStatement psta = conn.prepareStatement(sqlcomm);
            //判断命令中是否有参数，若没有参数，则把参数值的数组设置为0
            if (para == null) {
                para = new Object[0];
            }
            //遍历参数列表，并进行赋值
            for (int i = 0; i < para.length; i++) {
                psta.setObject(i + 1, para[i]);
            }
            //执行sql命令
            int i = psta.executeUpdate();
            if (i > 0) {
                flag = true;
            }
            close(null, psta, conn);
            return flag;
        } catch (SQLException e) {
            return false;
        }
    }

    /**
     * 用于执行查询命令
     *
     * @param cls  数据表所对应的实体类
     * @param sql  要执行的sql查询命令
     * @param para 要执行的sql命令中参数所对应的值，若没有则为null
     * @return 返回数据集，数据集中的第一个元素都是cls的对象
     */

    public List<T> query(Class<T> cls, String sql, Object... para) {
        List<T> list = new ArrayList<>();
        try {
            conn = getConn();
            PreparedStatement psta = conn.prepareStatement(sql);
            //判断命令中是否有参数，若没有参数，则把参数值的数组设置为0
            if (para == null) {
                para = new Object[0];
            }
            //遍历参数列表，并进行赋值
            for (int i = 0; i < para.length; i++) {
                psta.setObject(i + 1, para[i]);
            }
            ResultSet rs = psta.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();//rs中列的名称和类型的信息,并把它赋给rsmd,如：select id,name,pass from login，rsmd为得列名称为id,name,pass,列的类型为long、String、String等信息
            while (rs.next()) {
                T obj = cls.newInstance(); //创建这个类的新的实例
                int col = rsmd.getColumnCount();//获取rs中的列数据，取sql命令中所给的字段 数，如 select id,name,pass from login,则col=3
                //遍历rs中所有列
                for (int i = 1; i <= col; i++) {
                    String DBField = rsmd.getColumnLabel(i); //获取第i列名称
                    Field field = cls.getDeclaredField(DBField); //获取cls类中定的成员变量名与列名DBField
                    field.setAccessible(true); //私有可见
                    field.set(obj, rs.getObject(i));//把rs元素中的第i个列的值，赋给对象obj的field成员变量
                }
                list.add(obj);//obj添加到list中
            }
            close(rs, psta, conn);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }
}
